package com.banggood.upms.web;

import com.banggood.silk.web.api.exception.SkbException;
import com.banggood.upms.bean.exception.ExceptionEnum;
import com.banggood.upms.bean.po.Tree;
import com.banggood.upms.bean.po.TreeTree;
import com.banggood.upms.bean.vo.TreeTreeVo;
import com.banggood.upms.bean.vo.search.TreeTreeSearchCriteria;
import com.banggood.upms.bean.vo.validation.AdjustGroup;
import com.banggood.upms.bean.vo.validation.SearchGroup;
import com.banggood.upms.common.constant.UpmsConstant;
import com.banggood.upms.service.TreeService;
import com.banggood.upms.service.TreeTreeService;
import com.banggood.upms.converter.TreeTreeConverter;
import io.swagger.annotations.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @author XuChuangFeng
 */
@RequestMapping("/tree-tree")
@RestController
@Api(value = "树与树管理", description = "提供树节点与树节点的映射跟搜索接口。")
public class TreeTreeController {

    protected final Log logger = LogFactory.getLog(getClass());
    @Autowired
    private TreeTreeService treeTreeService;
    @Autowired
    private TreeTreeConverter treeTreeConverter;
    @Autowired
    private TreeService treeService;

    @RequestMapping(value = "/adjust", method = RequestMethod.POST)
    @ApiOperation(value = "树节点与树节点的映射分配，一个树节点（以下统称该“树节点”）可以配置多个其他树节点", notes = "POST请求")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fromTreeId", value = "要进行分配的树节点（也就是“该树节点”），该树节点将拥有配置多个其他树的节点", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "toTreeType", value = "要配置给“该树节点”的树节点的类型", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "newToTreeIds", value = "要配置给“该树节点”的树节点的数组，不传入则删除之前已分配的树节点", required = false, paramType = "query", dataType = "String"),
    })
    @ApiResponses({
            @ApiResponse(code = 2003, message = "必须指定树类型节点分配!"),
            @ApiResponse(code = 2008, message = "树节点不存在!"),
            @ApiResponse(code = 2009, message = "必须指定树节点ID!"),
            @ApiResponse(code = 2011, message = "被分配节点的树类型只能是岗位!")
    })
    public String assignTree(@Validated({AdjustGroup.class}) TreeTreeVo vo) throws Exception {
        // 需要传入树类型，否则其他树类型分配数据将会被删除
        if(vo.getToTreeType() == null) {
            throw new SkbException(ExceptionEnum.TREE_TYPE_CANT_BE_NULL.getCode(), ExceptionEnum.TREE_TYPE_CANT_BE_NULL.getMessage());
        }
        if(StringUtils.isEmpty(vo.getFromTreeId())) {
            throw new SkbException(ExceptionEnum.MISSING_TREE_ID.getCode(), ExceptionEnum.MISSING_TREE_ID.getMessage());
        }
        Tree fromTree = treeService.selectByPrimaryKey(vo.getFromTreeId());
        if(fromTree == null) {
            throw new SkbException(ExceptionEnum.NODE_NOT_EXISTS.getCode(), ExceptionEnum.NODE_NOT_EXISTS.getMessage());
        }
        if(!UpmsConstant.JOB.equalsIgnoreCase(fromTree.getTreeType())) {
            throw new SkbException(ExceptionEnum.FORBIDDEN_FROM_TREE_TYPE.getCode(), ExceptionEnum.FORBIDDEN_FROM_TREE_TYPE.getMessage());
        }
        /**
         * TODO 要判断传入的树节点是否属于这个树类型
         * #1, 查看之前是否为这个树节点分配过权限，如果没有就直接将此次添加的全部新增，返回
         * #2, 分配过映射树节点的话，要做比较，分配前A跟分配后B的集合的并集C不做任何操作，C在A中的绝对补集做删除操作，C在B中的绝对补集做新增操作。
         * #3, 逻辑跟用户分配树一样
         */
        logger.debug("本次操作的树节点主键：" + vo.getFromTreeId());
        String brief;
        // 前端没有传入任何的分配ID，newToTreeIds是空，直接删除所有已分配的
        if(CollectionUtils.isEmpty(vo.getNewToTreeIds())) {
            brief = treeTreeService.deleteAll(vo);
        } else {
            // #1, 根据树节点的ID找出这个节点已经分配过的权限
            TreeTreeSearchCriteria searchCriteria = new TreeTreeSearchCriteria();
            searchCriteria.setFromTreeId(vo.getFromTreeId());
            searchCriteria.setToTreeType(vo.getToTreeType());
            List<TreeTree> preAdjustTreeTreeMappings = treeTreeService.selectByFromTreeIdAndTreeType(searchCriteria);
            if(CollectionUtils.isEmpty(preAdjustTreeTreeMappings)) {
                brief =  treeTreeService.insertTreeTrees(treeTreeConverter.transferToPersistentList(vo));
            } else {
                // #2
                List<String> idsForRemove = new ArrayList<>();
                List<TreeTree> objForInsert = new ArrayList<>();
                // 初始化待删除列表跟带添加列表
                treeTreeConverter.prepareAdjustElements(vo, preAdjustTreeTreeMappings, idsForRemove, objForInsert);
                brief =  treeTreeService.adjustTreeTrees(objForInsert, idsForRemove);
            }
        }
        return brief;
    }

    @RequestMapping(value = "/search", method = RequestMethod.POST)
    @ApiOperation(value = "查看这个树节点已经分配的树节点映射", notes = "POST请求")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fromTreeId", value = "要进行分配的树节点（也就是“该树节点”），该树节点将拥有配置多个其他树的节点", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "toTreeType", value = "要配置给“该树节点”的树节点的类型", required = false, paramType = "query", dataType = "String"),
    })
    @ApiResponses({
            @ApiResponse(code = 2003, message = "必须指定树类型节点分配!"),
            @ApiResponse(code = 2009, message = "必须指定树节点ID!")
    })
    public List<TreeTree> selectTreeTreeMappings(@Validated({SearchGroup.class}) TreeTreeSearchCriteria criteria){
        List<TreeTree> treeTreeMappings = treeTreeService.selectByFromTreeIdAndTreeType(criteria);
        return treeTreeMappings;
    }
}